package com.aviatorscript.avitorscriptmust.validation;

import com.aviatorscript.avitorscriptmust.cache.AviatorValidationCacheManager;
import com.aviatorscript.avitorscriptmust.dto.ValidationResult;
import com.aviatorscript.avitorscriptmust.entity.FieldValidationConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * AviatorScript校验执行器
 * 负责执行具体的校验逻辑，支持嵌套对象和集合遍历
 *
 * @author system
 */
@Component
@Slf4j
public class AviatorValidationExecutor {
    
    @Autowired
    private AviatorValidationCacheManager cacheManager;
    
    /**
     * 执行AviatorScript校验
     * 
     * @param dto 要校验的对象
     * @return 校验结果
     */
    public ValidationResult validate(Object dto) {
        if (dto == null) {
            ValidationResult result = new ValidationResult();
            result.addErrorMessage("校验对象不能为null");
            return result;
        }
        
        String className = dto.getClass().getSimpleName();
        List<FieldValidationConfig> rules = cacheManager.getValidationRules(className);
        
        ValidationResult result = new ValidationResult()
            .setClassName(className)
            .setRuleCount(rules.size());
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 按优先级顺序执行所有校验规则
            for (FieldValidationConfig config : rules) {
                try {
                    executeValidationRule(dto, config, result);
                } catch (Exception e) {
                    log.error("执行校验规则异常: rule={}, fieldPath={}, error={}", 
                             config.getRuleName(), config.getFieldPath(), e.getMessage(), e);
                    result.addErrorMessage("校验规则执行异常: " + config.getRuleName());
                }
            }
            
        } catch (Exception e) {
            log.error("校验过程发生异常: className={}, error={}", className, e.getMessage(), e);
            result.addErrorMessage("校验过程发生异常: " + e.getMessage());
        }
        
        long elapsedTime = System.currentTimeMillis() - startTime;
        result.setElapsedTime(elapsedTime);
        
        log.debug("校验完成: className={}, valid={}, ruleCount={}, elapsedTime={}ms", 
                 className, result.isValid(), result.getRuleCount(), elapsedTime);
        
        return result;
    }
    
    /**
     * 执行单个校验规则
     * 
     * @param dto 校验对象
     * @param config 校验配置
     * @param result 校验结果（用于累积错误信息）
     */
    private void executeValidationRule(Object dto, FieldValidationConfig config, ValidationResult result) {
        try {
            // 准备AviatorScript执行环境
            Map<String, Object> env = new HashMap<>();
            env.put("dto", dto); // 整个DTO对象，用于复杂路径访问
            env.put("fieldPath", config.getFieldPath()); // 字段路径
            
            // 根据字段路径获取字段值
            Object fieldValue = getFieldValue(dto, config.getFieldPath());
            env.put("fieldValue", fieldValue); // 字段值
            
            // 执行已编译的AviatorScript脚本
            if (config.getCompiledExpression() == null) {
                log.warn("校验规则脚本未编译: ruleName={}", config.getRuleName());
                result.addErrorMessage("校验规则未正确初始化: " + config.getRuleName());
                return;
            }
            
            Object scriptResult = config.getCompiledExpression().execute(env);
            
            // 解析脚本返回结果
            handleScriptResult(config, scriptResult, result);
            
        } catch (Exception e) {
            log.error("执行校验脚本异常: rule={}, fieldPath={}, error={}", 
                     config.getRuleName(), config.getFieldPath(), e.getMessage(), e);
            result.addErrorMessage("校验脚本执行异常: " + config.getRuleName());
        }
    }
    
    /**
     * 处理脚本执行结果
     * 
     * @param config 校验配置
     * @param scriptResult 脚本执行结果
     * @param result 校验结果
     */
    private void handleScriptResult(FieldValidationConfig config, Object scriptResult, ValidationResult result) {
        if (scriptResult instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> resultMap = (Map<String, Object>) scriptResult;
            Boolean valid = (Boolean) resultMap.get("valid");
            
            if (valid == null || !valid) {
                String message = (String) resultMap.get("message");
                String errorMessage = message != null ? message : config.getErrorMessage();
                result.addErrorMessage(errorMessage);
                
                log.debug("校验失败: rule={}, fieldPath={}, message={}", 
                         config.getRuleName(), config.getFieldPath(), errorMessage);
            }
        } else {
            log.warn("校验脚本返回结果格式不正确: rule={}, result={}", 
                    config.getRuleName(), scriptResult);
            result.addErrorMessage("校验脚本返回格式错误: " + config.getRuleName());
        }
    }
    
    /**
     * 根据字段路径获取字段值（支持嵌套和数组）
     * 
     * @param obj 对象
     * @param fieldPath 字段路径，如：cartList[*].itemList[*].itemPrice
     * @return 字段值，如果是集合遍历则返回原对象供脚本处理
     */
    private Object getFieldValue(Object obj, String fieldPath) {
        try {
            // 如果字段路径包含[*]，说明是集合遍历，直接返回原对象供脚本处理
            if (fieldPath.contains("[*]")) {
                return obj;
            }
            
            // 普通字段路径处理
            String[] pathParts = fieldPath.split("\\.");
            Object currentObj = obj;
            
            for (String part : pathParts) {
                if (currentObj == null) {
                    return null;
                }
                
                // 获取字段值
                currentObj = getFieldValueByName(currentObj, part);
            }
            
            return currentObj;
            
        } catch (Exception e) {
            log.warn("获取字段值失败: fieldPath={}, error={}", fieldPath, e.getMessage());
            return null;
        }
    }
    
    /**
     * 通过字段名获取字段值
     * 
     * @param obj 对象
     * @param fieldName 字段名
     * @return 字段值
     */
    private Object getFieldValueByName(Object obj, String fieldName) {
        try {
            Class<?> clazz = obj.getClass();
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (NoSuchFieldException e) {
            // 尝试父类中的字段
            Class<?> superClass = obj.getClass().getSuperclass();
            if (superClass != null && superClass != Object.class) {
                try {
                    Field field = superClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    return field.get(obj);
                } catch (Exception ex) {
                    log.warn("在父类中也未找到字段: fieldName={}, class={}", fieldName, obj.getClass().getName());
                }
            }
            log.warn("字段不存在: fieldName={}, class={}", fieldName, obj.getClass().getName());
            return null;
        } catch (Exception e) {
            log.warn("获取字段值异常: fieldName={}, class={}, error={}", 
                    fieldName, obj.getClass().getName(), e.getMessage());
            return null;
        }
    }
} 